package com.white.loggerserver.core

import com.white.loggerserver.App
import com.white.loggerserver.L
import com.white.loggerserver.room.MyRoomDb
import com.white.loggerserver.room.Record
import java.io.File
import java.io.FileOutputStream
import java.net.Socket
import java.nio.ByteBuffer
import java.nio.charset.Charset
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.atomic.AtomicBoolean

/**
 * Created by ytf on 2020/07/23.
 * Description:
 */
class LogServerHandler(
    val ip: String,
    var client: Socket,
    var taskPool: ExecutorService,
    var callback: InnerListenCallback
) {

    private var alive = AtomicBoolean(false)
    private var sdf = SimpleDateFormat("yyyy-MM-dd", Locale.CHINA)

    private var fos : FileOutputStream? = null
    private val watchDog by lazy { WatchDog(3, ip) }
    private var record : Record? = null
    private val timeBuf = ByteBuffer.allocate(8);

    private var targetFilePath :File? = null

    init {
        try {

            val name = "${sdf.format(Date())}_${ip}.log"

            targetFilePath =  File(App.mAppContext.getExternalFilesDir(null), "/$name")


            record = MyRoomDb.instance.recordDao().findByName(sdf.format(Date()) + "_$ip")
            if(record == null){
                record = Record()
                record?.apply{
                    title = name
                    desc = "log"
                    addTime = Date().time
                    desc = "log"
                    path = targetFilePath?.absolutePath?:""
                    val id = MyRoomDb.instance.recordDao().addRecord(this)
                    rid = id
                }
            }
        }catch (e: Exception){
            L.e("异常出现${e.localizedMessage}")
        }
    }

    fun start(){
        taskPool.submit(ReadTask())
        callback.onClientOnline(ip)
    }

    private fun isActive() : Boolean{
        return !client.isClosed
                && client.isConnected
                && alive.get()
    }

    private inner class ReadTask : Runnable {

        override fun run() {

            val buffer = ByteArray(512)
            var len = 0
            watchDog.start{
                L.e("时间到了，写一波")
                fos?.apply {
                    flush()
                    close()
                }
                fos = null
            }
            alive.set(true)
            L.e("${ip}上线")
            while (isActive()) {
                try {
                    val inputStream = client.getInputStream()
                    inputStream?.let {
                        len =  inputStream.read(buffer)
                        if(len > 0){
                            handReceiveData(buffer, len)
                            watchDog.touch()
                        }else{
                            close()
                            return
                        }
                    }?: kotlin.run {
                        close()
                        return
                    }
                } catch (e: Exception) {
                    close()
                    return
                }
            }
        }
    }

    fun close() {
        alive.set(false)
        try {
            client.close()
            fos?.apply {
                flush()
                close()
            }
            fos = null
            callback.onClientOffline(ip)
            watchDog.stop()
            client.shutdownInput()
            client.shutdownOutput()
            L.e("${ip}下线")
        }catch (e: Exception){

        }
    }

    private val sdfHms = SimpleDateFormat("HH:mm:ss", Locale.CHINA)

    private fun handReceiveData(ret: ByteArray, read: Int) {

        if (read >= 13
            && ret[0] == 0xAA.toByte()
            && ret[1] == 0xAA.toByte()) {

            val type = ret[2].toInt()
            val tbuf = ByteArray(8)
            System.arraycopy(ret, 3, tbuf, 0, 8)

            timeBuf.clear()
            timeBuf.put(tbuf, 0, 8)
            timeBuf.flip()
            val stamp = timeBuf.long

            val msgLenBuf = ByteArray(2)
            System.arraycopy(ret, 11, msgLenBuf, 0, 2)
            val msgLen = (msgLenBuf[0].toInt() shl 8) or msgLenBuf[1].toInt()
            //加个换行符
            val msgBuf = ByteArray(msgLen+1)
            System.arraycopy(ret, 13, msgBuf, 0, msgLen)
            msgBuf[msgLen] = 0x0.toByte()
            try {
                val msg = String(msgBuf, Charset.defaultCharset())
                callback.onReceiveMsg(ip, type, stamp, msg)
                msgBuf[msgLen] = 0x0A.toByte()
                writeFile(msgBuf, 0, msgLen+1)
            }catch (e: Exception){
            }
        }
    }

    private fun writeFile(data : ByteArray, offset : Int, len : Int){
        try {

            if(fos == null){
                fos = FileOutputStream(targetFilePath, true)
            }
            fos?.write(data, offset, len)
        }catch (ex : java.lang.Exception){

        }
    }
}